#include "include/GUIMouseCursor.h"
#include "GUIGeometryBuffer.h"
#include "FormatString/GUIFormattedImageComponent.h"
#include "GUISystem.h"
#include "GUILogger.h"
#include "GUIBase.h"
#include "GUIError.h"
#include "Scheme/GUIImage.h"
#include "XML/GUIXMLCursorHandler.h"

namespace YGUI
{
    template<>
    MouseCursor* Singleton<MouseCursor>::m_singleton = 0;

    MouseCursor::MouseCursor(void) :
        m_geometry(&System::getSingleton().getRenderer()->createGeomertyBuffer()),
        m_image(0),
        m_delegate(0),
        m_invalidated(true)
    {
        m_geometry->setClipping(Rect<float>(Vector2<float>(), System::getSingleton().getRenderer()->getSize()));
    }

    MouseCursor::~MouseCursor(void)
    {
        if(m_image)
            delete m_image;
    }

    MouseCursor& MouseCursor::getSingleton(void)
    {
        static MouseCursor instance;
        return (*m_singleton);
    }

    MouseCursor* MouseCursor::getSingletonPtr(void)
    {
        if(!m_singleton)
            getSingleton();
        return m_singleton;
    }

    void MouseCursor::setPosition(const Vector2<float>& pt)
    {
        m_position = pt;
        m_geometry->setTranslation(Vector3<float>(pt.m_x, pt.m_y, 0.0f));
        //m_image->setPosition(pt);
        //m_invalidated = true;
    }

    void MouseCursor::draw(void) const
    {
        if(m_image && m_invalidated)
        {
            const Rect<float>& rc = m_image->getRect();
            m_image->draw(*m_geometry, 0, 0, rc.getHeight(), 0.0f);
            m_invalidated = false;
        }
        m_geometry->draw();
    }

    void MouseCursor::setCursor(FormattedImageComponent* img, bool destroy_last/* = true*/)
    {
        assert(img != 0);
        if(destroy_last)
            destroyImage();
        m_image = img;
        if(m_image)
        {
            m_delegate = GlobalEventset::getSingleton().addEvent(FormattedImageComponent::EventInvalidated, 
                this, &MouseCursor::onImageInvalidated);
        }
    }

    void MouseCursor::setCursor(const String& cursor)
    {
        if(!m_image)
        {
            m_image = MEMCHECK_NEW FormattedImageComponent;
            m_image->setAdaptive(true);
        }

        CursorMap::const_iterator it = m_cursorDefinitions.find(cursor);
        if(it != m_cursorDefinitions.end())
        {
            if(!m_delegate)
            {
                m_delegate = GlobalEventset::getSingleton().addEvent(FormattedImageComponent::EventInvalidated, 
                    this, &MouseCursor::onImageInvalidated);
            }
            switch(it->second.type)
            {
            case MouseCursor::RT_Image:
                {
                    const Image* img = ValueConverter::string2Image(it->second.value);
                    m_image->setImage(img);
                }
                break;
            case MouseCursor::RT_Animation:
                m_image->setAnimation(it->second.value);
                break;
            default: 
                assert(false);
                break;
            }
        }
        else
        {
            Logger::getSingleton().wprintf(L"MouseCursor::setCursor -- Cursor named \"%s\" is not "
                L"defined.\n", cursor.w_str());
        }
    }

    void MouseCursor::destroyImage(void)
    {
        if(m_image)
        {
            if(m_delegate)
                m_delegate->pickOff();
            m_delegate = 0;
            delete m_image;
            m_image = 0;
        }
    }

    void MouseCursor::invalidate(void)
    {
        m_geometry->reset();
        m_invalidated = true;
    }

    void MouseCursor::onImageInvalidated(const EventArgs& e)
    {
        const FmtComponentEventArgs& arg = (const FmtComponentEventArgs&)(e);
        if(arg.StringComponent == m_image)
            invalidate();
    }

    void MouseCursor::addCursor(const String& name, ResType type, const String& value)
    {
        CursorMap::iterator it = m_cursorDefinitions.find(name);
        if(it != m_cursorDefinitions.end())
        {
            Logger::getSingleton().wprintf(L"MouseCursor::addCursor -- Cursor named \"%s\" is "
                L"aleardy exists.\n", name.w_str());
            return;
        }
        if(value.empty())
        {
            Logger::getSingleton().wprintf(L"MouseCursor::addCursor -- The cursor image named \"%s\" "
                L"is invalid.\n", name.w_str());
            return;
        }
        m_cursorDefinitions.insert(std::make_pair(name, CursorResource(type, value)));
    }

    void MouseCursor::removeCursor(const String& name)
    {
        CursorMap::iterator it = m_cursorDefinitions.find(name);
        if(it == m_cursorDefinitions.end())
            return;
        else m_cursorDefinitions.erase(it);
    }

    bool MouseCursor::isCursorExists(const String& name) const
    {
        return (m_cursorDefinitions.find(name) != m_cursorDefinitions.end());
    }

    void MouseCursor::clearCursors(void)
    {
        m_cursorDefinitions.clear();
    }

    unsigned long MouseCursor::loadCursorsFromXML(const String& filename)
    {
        CursorXMLHandler handler;
        unsigned long err_code = System::getSingleton().getXMLParser()->parseXMLFile(handler, filename);
        if(err_code != ERRORCODE::GUI_ERROR_SUCCESS)
        {
            Logger::getSingleton().wprintf(L"MouseCursor::loadCursorsFromXML -- Load xml \"%s\" failed, "
                L"error code is %u.\n", filename.w_str(), err_code);
        }
        return err_code;
    }
}